package com.tang.server;

import com.alibaba.fastjson.JSON;
import com.tang.domain.ClientMsgProtocol;
import com.tang.util.ChannelHandler;
import com.tang.util.MsgUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * Server消息配置
 *
 * @author fulin.tang
 * @version V3.0
 * @since 2022/5/18 14:12
 */
@Slf4j
public class MyServerHandler extends ChannelInboundHandlerAdapter {

    private WebSocketServerHandshaker handshake;

    // 新的IP链接事件
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("有一个新连接上线，ID: {}, ADDRESS: {}", ctx.channel().id(), ctx.channel().localAddress());
        ChannelHandler.channelGroup.add(ctx.channel());
    }

    // IP断开事件
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.info("有一个连接下线，ID: {}, ADDRESS: {}", ctx.channel().id(), ctx.channel().localAddress());
        ChannelHandler.channelGroup.remove(ctx.channel());
    }

    // 异常事件
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        ctx.close();
        log.error("异常信息：\r\n{}", cause.getMessage());
    }

    // 接收到消息的事件
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        // http
        if (msg instanceof FullHttpRequest) {
            
            FullHttpRequest httpRequest = (FullHttpRequest) msg;
            
            // http消息没有成功的话
            if (!httpRequest.decoderResult().isSuccess()) {
                
                DefaultFullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
                
                // 返回应答给客户端
                if (httpResponse.status().code() != 200) {
                    ByteBuf byteBuf = Unpooled.copiedBuffer(httpResponse.status().toString(), CharsetUtil.UTF_8);
                    httpResponse.content().writeBytes(byteBuf);
                    byteBuf.release(); // 释放
                }

                // 如果是非Keep-Alive，关闭连接
                ChannelFuture channelFuture = ctx.channel().writeAndFlush(httpResponse);
                if (httpResponse.status().code() != 200) {
                    channelFuture.addListener(ChannelFutureListener.CLOSE);
                }

                return;
            }

            WebSocketServerHandshakerFactory wsFactory =
                    new WebSocketServerHandshakerFactory("ws:/" + ctx.channel() + "/websocket", null, false);
            handshake = wsFactory.newHandshaker(httpRequest);
            if (null == handshake) {
                WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
            } else {
                handshake.handshake(ctx.channel(), httpRequest);
            }

            return;

        }

        if (msg instanceof WebSocketFrame) {
            WebSocketFrame webSocketFrame = (WebSocketFrame) msg;
            // 关闭请求
            if (webSocketFrame instanceof CloseWebSocketFrame) {
                handshake.close(ctx.channel(), ((CloseWebSocketFrame) webSocketFrame).retain());
                return;
            }
            // PING请求
            if (webSocketFrame instanceof PingWebSocketFrame) {
                ctx.channel().write(new PongWebSocketFrame(webSocketFrame.content().retain()));
                return;
            }
            // 只支持文本格式，不支持二进制消息
            if (!(webSocketFrame instanceof TextWebSocketFrame)) {
                throw new Exception("仅支持文本格式");
            }

            String request = ((TextWebSocketFrame) webSocketFrame).text();
            log.info("服务端收到：{}", request);

            ClientMsgProtocol clientMsgProtocol = JSON.parseObject(request, ClientMsgProtocol.class);
            // 请求个人信息
            if (1 == clientMsgProtocol.getType()) {
                ctx.channel().writeAndFlush(MsgUtil.getInstance().buildMsgOwner(ctx.channel().id().toString()));
            }
            // 群发消息
            if (2 == clientMsgProtocol.getType()) {
                TextWebSocketFrame textWebSocketFrame = MsgUtil.getInstance().buildMsgAll(ctx.channel().id().toString(), clientMsgProtocol.getMsgInfo());
                ChannelHandler.channelGroup.writeAndFlush(textWebSocketFrame);
            }

        }

    }

}
